/*
EP3D is a real-time 3D planet engine , which in addition to providing 
substandard scene rendering and scene management, of course, it also 
provides some basic class libraries to build the entire virtual 
planet, or even the entire universe.

Copyright (C) 2010  Hongjiang Zhang	(zhjwyat@gmail.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef EP3D_MEMORY_H
#define EP3D_MEMORY_H

#ifndef EP3DCORE_MEM_MANAGE
	#define EP3DNew new
	#define EP3DDelete delete
	#define EP3DMalloc(size) malloc(size)
	#define EP3DFree(p) free(p)
#else
	#include "EP3DBase.h"
	#include "EP3DCriticalSection.h"
	#include "EP3DScoped.h"

	namespace EP3D
	{
		class Alloctor;
		class EP3DEXPORT Memory
		{
		public:
			struct Block 
			{
				size_t Size;
				const char* File;
				uint Line;
				const char* Function;
				bool IsArray;
				Block* Prev;
				Block* Next;
			};

			static size_t& MaxAllowedBytes() { Scoped s1(&ms_kLock); return ms_uiMaxAllocatedBytes; }
			static bool& TrackSizes() { Scoped s1(&ms_kLock); return ms_bTrackSize; }

			static size_t GetNumNewCalls() { Scoped s1(&ms_kLock); return ms_uiNumNewCalls; }
			static size_t GetNumDeletetCalls() { Scoped s1(&ms_kLock); return ms_uiNumDeleteCalls; }
			static size_t GetNumBlocks() { Scoped s1(&ms_kLock); return ms_uiNumBlocks; }
			static size_t GetNumBytes() { Scoped s1(&ms_kLock); return ms_uiNumBytes; }
			static size_t GetMaxAllocatedBytes() { Scoped s1(&ms_kLock); return ms_uiMaxAllocatedBytes; }
			static size_t GetMaxBlockSize() { Scoped s1(&ms_kLock); return ms_uiMaxBlockSize; }
			static size_t GetHistogram(int i) { Scoped s1(&ms_kLock); return ms_auiHistogram[i]; }

			static const Block* GetHead() { Scoped s1(&ms_kLock); return ms_pHead; }
			static const Block* GetTail() { Scoped s1(&ms_kLock); return ms_pTail; }

			static void ReportToFile(const char* acFilename);
			static void ReportToDebugger();

		private:
			static size_t ms_uiNumNewCalls;
			static size_t ms_uiNumDeleteCalls;

			static size_t ms_uiMaxAllowedBytes;

			static size_t ms_uiNumBlocks;

			static size_t ms_uiNumBytes;

			static Block* ms_pHead;
			static Block* ms_pTail;

			static bool ms_bTrackSize;

			static size_t ms_uiMaxAllocatedBytes;

			static size_t ms_uiMaxBlockSize;

			static size_t ms_auiHistogram[32];

			static CriticalSection ms_kLock;

			static void InsertBlock(Block* pBlock);
			static void RemoveBlock(Block* pBlock);

		public:
			static void* Allocate(Alloctor* allocator, size_t uiSize, const char* acFile, uint uiLine, const char* acFunction, bool bIsArray);
			static void Deallocate(Alloctor* allocator, char* pvAddr, bool bIsArray);
		};
	}// end namespace EP3D

#define  EP3DNew new(__FILE__, __LINE__, __FUNCTION__)
#define  EP3DDelete delete
#define	 EP3DMalloc(size) _EP3DMalloc(size, __FILE__, __LINE__, __FUNCTION__)
#define  EP3DFree(p) _EP3DFree(p)

inline void* operator new (size_t uiSize);
inline void* operator new[] (size_t uiSize);
inline void* operator new (size_t uiSize, const char* acFile, unsigned int uiLine, const char* acFunction);
inline void* operator new[] (size_t uiSize, const char* acFile, unsigned int uiLine, const char* acFunction);
inline void operator delete (void* pvAddr);
inline void operator delete[] (void* pvAddr);
inline void operator delete (void* pvAddr, const char* acFile, unsigned int uiLine, const char* acFunction);
inline void operator delete[] (void* pvAddr, const char* acFile, unsigned int uiLine, const char* acFunction);

EP3DEXPORT void* _EP3DMalloc(size_t uiSize, const char* acFile, unsigned int uiLine, const char* acFunction);
EP3DEXPORT void _EP3DFree(void* pvAddr);

#include "EP3DMemory.inl"

#endif
#endif